package com.pig4cloud.pig.ads.gdt.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.pig4cloud.pig.ads.gdt.service.GdtAccesstokenService;
import com.pig4cloud.pig.ads.gdt.service.IGdtCampaignService;
import com.pig4cloud.pig.ads.pig.mapper.gdt.GdtCampaignMapper;
import com.pig4cloud.pig.ads.utils.OEHttpUtils;
import com.pig4cloud.pig.common.core.exception.CheckedException;
import com.pig4cloud.pig.api.entity.ResponseBean;
import com.pig4cloud.pig.api.enums.GdtCampaignEnum;
import com.pig4cloud.pig.api.gdt.dto.FilteringDto;
import com.pig4cloud.pig.api.gdt.dto.GdtCampaignDto;
import com.pig4cloud.pig.api.gdt.dto.GdtCreateCampaignDto;
import com.pig4cloud.pig.api.gdt.dto.GdtUpdateCampaignDto;
import com.pig4cloud.pig.api.gdt.entity.GdtCampaign;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.util.SecurityUtils;
import com.pig4cloud.pig.api.gdt.vo.GdtCampaignVo;
import com.pig4cloud.pig.api.util.JsonUtil;
import com.pig4cloud.pig.api.util.MapUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 广点通-推广计划 服务层实现
 *
 * @author hma
 * @date 2020-12-03
 */
@Log4j2
@Service
public class GdtCampaignServiceImpl extends ServiceImpl<GdtCampaignMapper, GdtCampaign> implements IGdtCampaignService {

	@Autowired
	private GdtAccesstokenService gdtAccesstokenService;
	/**
	 * 开启事务
	 */
	@Autowired
	private DataSourceTransactionManager dataSourceTransactionManager;
	@Autowired
	private TransactionDefinition transactionDefinition;
	@Value(value = "${gdt_url}")
	private String gdtUrl;

	@Value(value = "${gdt_promoted_object_url}")
	private String gdtPromotedObjectUrl;
	@Value(value = "${gdt_campaigns_add_url}")
	private String gdtCampaignAddUrl;
	@Value(value = "${gdt_campaigns_get}")
	private String gdtCampaignsGetUrl;
	@Value(value = "${gdt_campaigns_update_url}")
	private String gdtCampaignsUpdateUrl;
//	@Value(value = "${spring.profiles.active}")
//	private String springProfilesActive;
	@Value(value = "${gdt.configured.status}")
	private String configuredStatus;



	@Override
	public R createGdtCampaign(GdtCreateCampaignDto createCampaignDto) {
		//本地，测试环境 状态设置为暂停，线上设置为启动
		//验证推广名称是否重复
		//调用三方
		//调用三方成功，存储到本地
		//下调日预算不能低于该推广计划今日已消耗金额的 1.5 倍
		//每次修改幅度不能低于 5000 分（50 元，单位为人民币）
		try {
			Integer userId = SecurityUtils.getUser().getId();
			List<GdtCampaign> gdtCampaignList = baseMapper.selectList(Wrappers.<GdtCampaign>query().lambda().eq(GdtCampaign::getCampaignName,createCampaignDto.getCampaignName()).eq(GdtCampaign::getAccountId,createCampaignDto.getAccountId()));
			if (CollectionUtils.isNotEmpty(gdtCampaignList)) {
				return R.failed("该推广计划下推广名称已存在");
			}
			if(createCampaignDto.getCampaignName().length() > 60){
				return R.failed("推广计划名称最长不能超过60个长度");
			}
			createCampaignDto.setConfiguredStatus(configuredStatus);
			//将大小写转换为下划线，小写
			String jsonString = JsonUtil.toUnderlineJSONString(createCampaignDto);
			Map<String, Object> paramMap = JsonUtil.parseJSON2Map(jsonString);
			JSONObject jsonObject = createOrGetPostThirdResponse(createCampaignDto.getAccountId().toString(), "createGdtCampaign", gdtCampaignAddUrl, paramMap);
			Long campaignId;
			if (null != jsonObject) {
				campaignId = jsonObject.getLong("campaign_id");
				createCampaignDto.setCampaignId(campaignId);
				String timestamp = String.valueOf(System.currentTimeMillis()/1000);
				Integer time = Integer.valueOf(timestamp);
				createCampaignDto.setCreatedTime(time.longValue());
				createCampaignDto.setLastModifiedTime(time.longValue());
				createCampaignDto.setIsDeleted("false");
				createCampaignDto.setUserId(userId.longValue());
				baseMapper.insert(createCampaignDto);
			}
			if(null != createCampaignDto.getDailyBudget()){
				createCampaignDto.setDailyBudget(createCampaignDto.getDailyBudget().divide(new BigDecimal(100)));
			}
			return R.ok(createCampaignDto);

		} catch (Exception e) {
			log.error("createGdtCampaign is error", e);
			String messsage=e.getMessage();
			if(StringUtils.isNotBlank(messsage)){
				if(messsage.contains("BusinessException:")){
					String substring0=messsage.substring(0, messsage.indexOf(":"));
					messsage= messsage.substring(substring0.length()+1);
				}

			}else{
				messsage="服务器异常，请稍后重试";
			}
			return R.failed("创建推广计划异常", messsage);
		}

	}


	/**
	 * 根据条件查询推广计划列表
	 *
	 * @param gdtCampaign
	 * @return
	 */
	@Override
	public List<GdtCampaign> gdtCampaignList(GdtCampaign gdtCampaign) {
		QueryWrapper queryWrapper=new QueryWrapper<GdtCampaign>(gdtCampaign);
		return   baseMapper.selectList(queryWrapper);
	}


	@Override
	public R getGtdCampaign(GdtCampaignDto gtdCampaignDto) {
		//  查询推广计划，过滤掉删除的状态
		// 分页查询推广计划列表
		//todo  处理不同的推广目标类型 文字描述
		gtdCampaignDto.setPromotedObjectType("PROMOTED_OBJECT_TYPE_APP_ANDROID");
		LambdaQueryWrapper<GdtCampaign> queryWrapper=Wrappers.<GdtCampaign>query().lambda().and(wrapper -> wrapper.eq(GdtCampaign::getAccountId, gtdCampaignDto.getAccountId())).and(StringUtils.isNotBlank(gtdCampaignDto.getAccountId()), wrapper -> wrapper.eq(GdtCampaign::getIsDeleted, "false")).eq(GdtCampaign::getPromotedObjectType,"PROMOTED_OBJECT_TYPE_APP_ANDROID").orderByDesc(GdtCampaign::getCampaignId);
		if(StringUtils.isNotBlank(gtdCampaignDto.getCampaignName())){
			queryWrapper.like(GdtCampaign::getCampaignName, gtdCampaignDto.getCampaignName());
		}
		IPage<GdtCampaign> page= this.page(new Page<>(gtdCampaignDto.getCurrent(),gtdCampaignDto.getSize()),queryWrapper);
		if(CollectionUtils.isNotEmpty(page.getRecords())){
			page.getRecords().forEach(c->{
				if(null != c.getDailyBudget()){
					c.setDailyBudget(c.getDailyBudget().divide(new BigDecimal("100")).setScale(2));
				}

			});
		}
		return R.ok(page);

	}

	//todo  匹配三方接口的类型和格式，已经长度
	//todo  定义推广目标字段库，按照展示的形式定义格式，支持的用  flag=true  标识
	//todo 当 campaign_type 取值 CAMPAIGN_TYPE_NORMAL  目前仅支持该计划类型
	@Override
	public R getGtdCampaignPromote(GdtCampaignDto gtdCampaignDto) {
		//返回对应支持的推广目标 及推广目标对象内容
		String fields = "promoted_object_name,promoted_object_id,promoted_object_type,promoted_object_spec";
		List<JSONArray> jsonObjectList = getThirdResponse(gtdCampaignDto.getAccountId(), "getGtdCampaign", gdtPromotedObjectUrl, null, null, fields,Boolean.TRUE);
		List<String> promoteTypeList = new ArrayList<>();
		List<PromoteObjectType> promoteObjectTypeList = null;
		if (CollectionUtils.isNotEmpty(jsonObjectList)) {
			//todo  字典替换
			jsonObjectList.forEach(ps -> {
				ps.forEach(p -> {
					JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(p));
					promoteTypeList.add(jsonObject.getString("promoted_object_type"));
				});
			});
			String promoteTypes = "PROMOTED_OBJECT_TYPE_LINK,PROMOTED_OBJECT_TYPE_LINK_WECHAT,PROMOTED_OBJECT_TYPE_ECOMMERCE,PROMOTED_OBJECT_TYPE_APP_ANDROID,PROMOTED_OBJECT_TYPE_APP_IOS,PROMOTED_OBJECT_TYPE_APP_ANDROID_MYAPP" +
					",PROMOTED_OBJECT_TYPE_APP_ANDROID_UNION,PROMOTED_OBJECT_TYPE_LOCAL_ADS_WECHAT,PROMOTED_OBJECT_TYPE_QQ_MESSAGE,PROMOTED_OBJECT_TYPE_LEAD_AD,PROMOTED_OBJECT_TYPE_MINI_GAME_WECHAT,PROMOTED_OBJECT_TYPE_MINI_GAME_QQ,APP_PROMOTE";
			List<PromoteObjectType> promoteObjectTypeArrayList = new ArrayList<>();
			Arrays.asList(promoteTypes.split(",")).forEach(t -> {
						PromoteObjectType promoteObjectType = new PromoteObjectType();
						promoteObjectType.setName(t);
						promoteObjectType.setValue(getTypeValue(t));
						if (promoteTypeList.contains(t)) {
							promoteObjectType.setFlag(Boolean.TRUE);
						}
						promoteObjectTypeArrayList.add(promoteObjectType);
					}

			);
			promoteObjectTypeList = recursion(promoteObjectTypeArrayList);
		}
		if (CollectionUtils.isEmpty(promoteObjectTypeList)) {
			return R.failed("当前没有可支持的推广目标");
		}
		return R.ok(promoteObjectTypeList);
	}


	/**
	 * 遍历将app应用放到app子list
	 *
	 * @param list
	 * @return
	 */
	public List<PromoteObjectType> recursion(List<PromoteObjectType> list) {
		List treeList = Lists.newArrayList();
		list.forEach(promoteObjectType -> {
			if (promoteObjectType.getName().equals("APP_PROMOTE")) {
				//todo 支持app ，先写死
				promoteObjectType.setFlag(Boolean.TRUE);
				treeList.add(addChild(promoteObjectType, list));
			} else {
				if (promoteObjectType.getName().indexOf("APP") <= 0) {
					treeList.add(promoteObjectType);
				}

			}
		});

		return treeList;
	}


	/**
	 * 查询推广计划模板
	 * @param gdtCampaignDto
	 * @return
     */
	@Override
	public R getGtdCampaignTemplate(GdtUpdateCampaignDto gdtCampaignDto){
		Integer userId= SecurityUtils.getUser().getId();
		gdtCampaignDto.setUserId(userId.longValue());
		LambdaQueryWrapper<GdtCampaign> queryWrapper= Wrappers.<GdtCampaign>query().lambda()
				.and(wrapper -> wrapper.eq(GdtCampaign::getAccountId, gdtCampaignDto.getAccountId()))
				.and(StringUtils.isNotBlank(gdtCampaignDto.getAccountId()), wrapper -> wrapper.eq(GdtCampaign::getUserId, gdtCampaignDto.getUserId()))
				.orderByDesc(GdtCampaign::getCreatedTime)
				.last("LIMIT 1");
		//查询此用户最后一次创建的广告组信息
		List<GdtCampaign> gdtCampaignList =baseMapper.selectList(queryWrapper);
		if(CollectionUtils.isNotEmpty(gdtCampaignList)){
			GdtCampaign gdtCampaign=gdtCampaignList.get(0);
			if(null != gdtCampaign.getDailyBudget()){
				gdtCampaign.setDailyBudget(gdtCampaign.getDailyBudget().divide(new BigDecimal(100)));
			}
			return R.ok(gdtCampaign);
		}
		return R.ok();
	}


	public PromoteObjectType addChild(PromoteObjectType promoteObjectType, List<PromoteObjectType> list) {
		List<PromoteObjectType> childList = Lists.newArrayList();
		promoteObjectType.setPromoteObjectTypeList(childList);
		for (PromoteObjectType childMap : list) {
			if (childMap.getName().indexOf("_APP") > 0) {
				childList.add(childMap);
			}
		}
		return promoteObjectType;
	}


	/**
	 * 调用广点通三方拉取列表接口
	 *
	 * @return
	 */
	@Override
	public List<JSONArray> getThirdResponse(String accountId, String methodName, String interfaceUrl, List<FilteringDto> filteringDtos, Map<String, String> paramMap, String fields,Boolean isPage) {
		try {
			Map<String, String> data = new HashMap<>();
			data.put("account_id", accountId);
			if (StringUtils.isNotBlank(fields)) {
				String[] field=fields.split(",");
				data.put("fields", JSONObject.toJSONString(field));
			}
			if (null != paramMap) {
				data.putAll(paramMap);
			}
			if(isPage){
				data.put("page_size", "10");//默认值：10。最小值 1，最大值 100
			}
			Integer page = 1;
			//获取广点通公共报文头
			List<JSONArray> list = new ArrayList<>();
			//todo  获取当前广告账号授权token
			while (true) {
				Map<String, String> commondata = gdtAccesstokenService.fetchAccesstoken(accountId);
				data.putAll(commondata);
				if(isPage){
					data.put("page", page.toString());  //默认值：1。最小值 1，最大值 99999
				}
				if (CollectionUtils.isNotEmpty(filteringDtos)) {
					data.put("filtering", JSONObject.toJSONString(filteringDtos));
				}
				String urlstr = gdtUrl + interfaceUrl + "?" + MapUtils.queryString(data);
				log.info(methodName + " request:" + urlstr);
				String resultStr = OEHttpUtils.doGdtGet(urlstr, null);
				log.info(methodName + " response:" + resultStr);
				ResponseBean resBean = JSON.parseObject(resultStr, ResponseBean.class);
				if (resBean != null && StringUtils.equals(resBean.getCode(), "0")) {
					if(null != resBean.getData().getJSONObject("page_info")){
						list.add(resBean.getData().getJSONArray("list"));
						Long totalPage = resBean.getData().getJSONObject("page_info").getLong("total_page");//总页数
						if (new BigInteger(String.valueOf(page)).compareTo(new BigInteger(String.valueOf(totalPage))) >= 0) {
							break;
						}
						page++;
					}else{
						if(null != resBean.getData()){
							JSONArray jsonArray=new JSONArray();
							jsonArray.add(resBean.getData());
							list.add(jsonArray);
						}

						break;
					}

				} else {
					break;

				}
			}
			return list;
		} catch (Exception e) {
			log.error(methodName + " getThirdResponse  is error", e);
			throw new CheckedException("服务器请求异常");
		}


	}


	/**
	 * 调用广点通创建接口(或者post 请求查询接口)
	 *
	 * @return
	 */
	@Override
	public JSONObject createOrGetPostThirdResponse(String accountId, String methodName, String interfaceUrl, Map<String, Object> data) {
		try {
			data.put("account_id", accountId);
			//获取广点通公共报文头
			//获取当前广告账号授权token
			Map<String, String> commondata = gdtAccesstokenService.fetchAccesstoken(accountId);
			data.putAll(commondata);
			String urlstr = gdtUrl + interfaceUrl + "?" + MapUtils.queryString(commondata);
			log.info(methodName + " request:" + urlstr);
			log.info(methodName + " data:" + JSON.toJSONString(data));
			String resultStr = OEHttpUtils.doPost(urlstr, data);
			//log.info(methodName + " response:" + resultStr);
			ResponseBean resBean = JSON.parseObject(resultStr, ResponseBean.class);
			if (StringUtils.equals(resBean.getCode(), "0")) {
				JSONObject jsonObject = resBean.getData();
				return jsonObject;
			} else {
				String messasgeCn = resBean.getMessage_cn();
				if(StringUtils.isNotBlank(messasgeCn) && messasgeCn.indexOf("trace_id") > 0){
					messasgeCn=messasgeCn.substring(0, messasgeCn.indexOf("trace_id"));
				}
				throw new CheckedException(messasgeCn);
			}
		} catch (Exception e) {
			log.error(methodName + " createThirdResponse  is error", e);
			throw new CheckedException(e.getMessage());
		}

	}


	private String getTypeValue(String type) {
		if (StringUtils.isBlank(type)) {
			type = "APP";
		}
		//todo  转载字典表
		switch (type) {
			case "PROMOTED_OBJECT_TYPE_LINK":
				return "网页";
			case "PROMOTED_OBJECT_TYPE_LINK_WECHAT":
				return "网页（微信推广）";
			case "PROMOTED_OBJECT_TYPE_ECOMMERCE":
				return "电商推广";
			case "PROMOTED_OBJECT_TYPE_APP_ANDROID":
				return "Android应用";
			case "PROMOTED_OBJECT_TYPE_APP_IOS":
				return "IOS应用";
			case "PROMOTED_OBJECT_TYPE_APP_ANDROID_MYAPP":
				return "应用宝推广";
			case "PROMOTED_OBJECT_TYPE_APP_ANDROID_UNION":
				return "Android应用（联盟推广)";
			case "PROMOTED_OBJECT_TYPE_LOCAL_ADS_WECHAT":
				return "本地广告（微信推广）";
			case "PROMOTED_OBJECT_TYPE_QQ_MESSAGE":
				return "QQ 消息";
			case "PROMOTED_OBJECT_TYPE_LEAD_AD":
				return "销售线索";
			case "PROMOTED_OBJECT_TYPE_MINI_GAME_WECHAT":
				return "微信小游戏";
			case "PROMOTED_OBJECT_TYPE_MINI_GAME_QQ":
				return "QQ 小游戏";
			default:
				return "应用推广";
		}
	}

	/**
	 * 修改推广计划信息
	 *
	 * @param gdtCampaignDto
	 * @return
	 */
	@Override
	public R updateGtdCampaignInfo(GdtUpdateCampaignDto gdtCampaignDto) {
		if (null == gdtCampaignDto) {
			return R.failed("参数不能为空");
		}
		if (StringUtils.isBlank(gdtCampaignDto.getAccountId())) {
			return R.failed("广告投放账号不允许为空");
		}
		if (StringUtils.isBlank(gdtCampaignDto.getCampaignId())) {
			return R.failed("广告计划ID不允许为空");
		}
		Integer configuredStatus = gdtCampaignDto.getConfiguredStatus();
		if (configuredStatus == null || configuredStatus < 0 || configuredStatus > 1) {
			return R.failed("请选择推广计划预算开关");
		}
		Map<String, String> map = gdtAccesstokenService.fetchAccesstoken(gdtCampaignDto.getAccountId());
		if (map == null || StringUtils.isEmpty(map.get("access_token"))) {
			return R.failed("广点通账户授权失败，请重试！");
		}
		String urlstr = gdtUrl + gdtCampaignsUpdateUrl + "?" + MapUtils.queryString(map);
		log.info("修改广点通广告计划 request:" + urlstr);
		Map<String, Object> params = new HashMap<>();
		params.put("account_id", gdtCampaignDto.getAccountId());
		params.put("campaign_id", gdtCampaignDto.getCampaignId());
		//默认为有效状态
		String configuredStatuType = GdtCampaignEnum.AD_STATUS_NORMAL.getType();
		String msg = "开启";
		if (configuredStatus - 1 == 0) {
			//暂停状态
			configuredStatuType = GdtCampaignEnum.AD_STATUS_SUSPEND.getType();
			msg = "暂停";
		}
		params.put("configured_status", configuredStatuType);
		//开启事务
		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		try {
			//修改数据库。推广计划表的用户配置状态
			GdtCampaign gtdCampaign = new GdtCampaign();
			gtdCampaign.setCampaignId(Long.parseLong(gdtCampaignDto.getCampaignId()));
			gtdCampaign.setConfiguredStatus(configuredStatuType);
			int rows = baseMapper.updateById(gtdCampaign);
			//事务未提交时，影响行数有值
			if (rows < 1) {
				return R.failed(msg + "广告计划预算预警失败！ Database operation failed");
			}
			//提交请求广点通修改推广计划接口
			String resultStr = OEHttpUtils.doPost(urlstr, params);
			//log.info("修改广点通广告计划： response:" + resultStr);
			ResponseBean resBean = JSON.parseObject(resultStr, ResponseBean.class);
			if (StringUtils.equals(resBean.getCode(), "0")) {
				//同步修改数据库
				JSONObject data = resBean.getData();
				if (data != null) {
					String campaignId = data.getString("campaign_id");
					if (StringUtils.isNotEmpty(campaignId)) {
						//接口执行成功，提交事务
						dataSourceTransactionManager.commit(transactionStatus);
						return R.ok("成功" + msg + "广告计划预算预警！");
					}
				}
			}
		} catch (Exception e) {
			log.error("修改推广计划 is error", e);
			//接口执行失败，回滚事务,防止数据库数据与广点通数据不统一
			dataSourceTransactionManager.rollback(transactionStatus);
			return R.failed(msg + "广告计划预算预警异常！" + e.getMessage());
		}
		//接口执行失败，回滚事务,防止数据库数据与广点通数据不统一
		dataSourceTransactionManager.rollback(transactionStatus);
		return R.failed(msg + "广告计划预算预警失败，请重试！");
	}

	/**
	 * 推广目标类型
	 */
	class PromoteObjectType {
		List<PromoteObjectType> promoteObjectTypeList;
		private String name;
		private String value;
		private Boolean flag = Boolean.FALSE;

		public PromoteObjectType() {
		}

		public PromoteObjectType(String name, String value) {
			this.name = name;
			this.value = value;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}

		public Boolean getFlag() {
			return flag;
		}

		public void setFlag(Boolean flag) {
			this.flag = flag;
		}

		public List<PromoteObjectType> getPromoteObjectTypeList() {
			return promoteObjectTypeList;
		}

		public void setPromoteObjectTypeList(List<PromoteObjectType> promoteObjectTypeList) {
			this.promoteObjectTypeList = promoteObjectTypeList;
		}
	}


	//todo  对应删除推广计划，广告组，创意接口  暂定


	@Override
	public int update(GdtCampaignVo req) {
		return baseMapper.update(req);
	}
}
